<?php

namespace App\Http\Middleware;

use Closure;
use Log;
use App\Utils\CommonUtils;
use App\Utils\ReturnUtils;
use App\Utils\RouteLists;
use App\Models\User;
use Auth;
use DB;
use App\Models\Common\Stopwords;
use Dotenv;
use App\Cache\BaseCache;
use Config;
use Cache;
use Redis;

class BeforeMiddleware {

    protected $DEBUG = TRUE; //调试接口总开关
    protected $CACHE_ON = FALSE; //缓存总开关
    
    public function handle($request, Closure $next) {
        /***********************读取环境变量**************************** */
        if ($request->input('debug') == 'debug') {// 先加载者先成功
            (new Dotenv\Dotenv(__DIR__ . '/../../../env/', 'debug.env'))->load();
        }
        $env_file = env($_SERVER['HTTP_HOST']);
        try {
            (new Dotenv\Dotenv(__DIR__ . '/../../../env/', $env_file . '.env'))->load();
        } catch (InvalidArgumentException $e) {
            
        }

        /**         * ********************测试函数********************** */
        if (env('OPEN_QUREYLOG')) {
            DB::connection(env('MYSQL_CONNECTION', 'mysql'))->enableQueryLog(); //开启sql语言分析
        }
        /**         * ************************************************* */
        
        /***********************请求过滤，参数校验层**************************** */
        $returnUtils = new ReturnUtils($request);

        $CUR_IP = $request->ip();
        $is_white_ip = FALSE;
        $i = 0;
        while (1) {
            $i++;
            $index_ip = env('IP_WHITE_' . $i, 'END');
            if ($index_ip == 'END') {
                break;
            } else if ($CUR_IP && $index_ip == $CUR_IP || $index_ip == trim(substr($CUR_IP, 0, -strlen(strrchr($CUR_IP, '.'))))) {
                $is_white_ip = TRUE;
                break;
            }
        }
        if (!$is_white_ip) {
            //黑名单
            $IPBlackCache = new BaseCache();
            $IPBlackCache->method = 'get';
            $IPBlackCache->cacheName = 'IPBlack';
            $IPBlackCache->cachePar = array($CUR_IP); //集合
            //IP 访问记录
            $IPBlackHistoryCache = new BaseCache();
            $IPBlackHistoryCache->method = 'get';
            $IPBlackHistoryCache->cacheName = 'IPBlackHistory';
            $IPBlackHistoryCache->cachePar = array($CUR_IP); //集合

            $caheObject = $IPBlackCache->HandleCache();
            if ($caheObject !== 'NO_CACHE') {
                return $returnUtils->returnError($returnUtils->return['ERROR_LIMIT_IP']);
            }
            $caheObject = $IPBlackHistoryCache->HandleCache();
            if ($caheObject !== 'NO_CACHE') {
                $times = $caheObject;
                if ($times > 2000 && !env('APP_DEBUG', FALSE)) {
                    //加入黑名单
                    $IPBlackCache->method = 'put';
                    $IPBlackCache->HandleCache();
                    Log::info('IP黑名单:+' . $CUR_IP . ' Times:' . $times);
                    return $returnUtils->returnError($returnUtils->return['ERROR_LIMIT_IP']);
                }
                $times = $times > 1 ? ++$times : 1;
                if ($times > 0 && $times % 100 === 0) {
                    Log::info('IP:' . $CUR_IP . ' Times = n*100,n =' . $times / 100);
                }
                $IPBlackHistoryCache->method = 'increment';
                $IPBlackHistoryCache->HandleCache();
            } else {
                $IPBlackHistoryCache->method = 'put';
                $IPBlackHistoryCache->cacheValue = 1;
                $IPBlackHistoryCache->HandleCache();
            }
        }
        $action = substr($request->route()[1]['uses'], 21);
        //参数验证
        $routelists = with(new RouteLists())->lists;
        if(isset($routelists[$action])){
            $route = $routelists[$action];
            //对比版本，查找相应规则
            $version = $request->input('v', '');
            if (isset($route['version'][$version])) {
                $rules_code = $route['version'][$version];
            } else if (isset($route['version']['max'])) {
                $rules_code = $route['version']['max'];
            } else {
                $message = array('en' => '', 'zh-CN' => 'routelists 异常错误');
                return $returnUtils->returnError($returnUtils->return['ERROR_UNKNOWN'], $message);
            }
            if (!isset($route['rules'][$rules_code])) {
                $message = array('en' => '', 'zh-CN' => 'routelists 异常错误');
                return $returnUtils->returnError($returnUtils->return['ERROR_UNKNOWN'], $message);
            }
            $rules = $route['rules'][$rules_code]; //得到验证规则
            //参数校验param
            $params = $request->all();

            if(isset($rules['times']) && $rules['times'] > 0 ){
                $tn = $request->input('tn');
                //times 每分钟限制次数，ip+token
                $LimitTimesPerMinCache = new BaseCache();
                $LimitTimesPerMinCache->method = 'get';
                $LimitTimesPerMinCache->cacheName = 'LIMIT_TIMES_PER_MIN';
                $LimitTimesPerMinCache->cachePar = array($CUR_IP,$tn); //集合
                $caheObject = $LimitTimesPerMinCache->HandleCache();
                if ($caheObject !== 'NO_CACHE') {
//                    Log:info('LIMIT_TIMES_PER_MIN :'.$caheObject);
                    if ($caheObject > $rules['times'] && !env('APP_DEBUG', FALSE)) {
                        //过于频繁
                        return $returnUtils->returnError($returnUtils->return['ERROR_LIMIT_TIMES']);
                    }
                    $LimitTimesPerMinCache->method = 'increment';
                    $LimitTimesPerMinCache->HandleCache();
                } else {
                    $LimitTimesPerMinCache->method = 'put';
                    $LimitTimesPerMinCache->cacheValue = 1;
                    $LimitTimesPerMinCache->HandleCache();
                }

            }

            //是否校验tn
            //        ty     String   //系统类型 a:android i:ios tv:电视端
            //        v      String   //软件版本号  1.0.0
            //        dk     String   //设备的唯一标示
            //        tn     String   //请求
            //        userId String   //若用户登录时传入用户id，若没有登陆时 ‘#ray’+ 随机16位字符 
            //        注：tn = 登陆时获取的用户token／随机16位字符包含数字 + md5(userId+ty+v+dk,32)，注意顺序不能改变，这样做的目的是为了每次接口都先校验请求的合法性
            if (isset($rules['isCheckTn']) && $rules['isCheckTn'] === TRUE) {
                $ty = $request->input('ty');
                $v = $request->input('v');
                $dk = $request->input('dk');
                $tn = $request->input('tn');
                $userId = $request->input('userId');
                if (substr($tn, -32) !== md5($userId . $ty . $v . $dk)) {
                    return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_VLAUE_TOKEN']);
                }
                $tn = substr($tn, 0, strlen($tn) - 32);
                $request->merge(array('tn' => $tn));
            }
            //isStrict 非常严格
            if ($rules['isStrict'] === 2 && count($params) !== count($rules['parameters'])) {
                $message = array('en' => '', 'zh-CN' => '参数个数不正确');
                return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_TOTAL'], $message);
            }
            $ip_withe = TRUE;
            //IP 白名单
            if (isset($rules['ipWithe']) && is_array($rules['ipWithe'])) {
                foreach ($rules['ipWithe'] as $value) {
                    $ip_withe = FALSE;
                    if ($value == $CUR_IP || $value == trim(substr($CUR_IP, 0, -strlen(strrchr($CUR_IP, '.'))))) {
                        $ip_withe = TRUE;
                        break;
                    }
                }
            }
//            if (!$ip_withe) {
//                $message = array('en' => '', 'zh-CN' => '不在IP白名单内:');
//                return $returnUtils->returnError($returnUtils->return['ERROR_IP_WHITE'], $message);
//            }
            foreach ($params as $key => $param) {
                if (!array_key_exists($key, $rules['parameters']) && $rules['isStrict'] !== 0) {
                    $message = array('en' => '', 'zh-CN' => '未知参数:' . $key);
                    return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_UNKONWN'], $message);
                }
                if (isset($rules['parameters'][$key]['isNull']) && $rules['parameters'][$key]['isNull'] === FALSE && $param === '') {
                    $message = array('en' => '', 'zh-CN' => '参数不能为空:' . $key);
                    return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_NULL'], $message);
                }
                if ($param !== '' && isset($rules['parameters'][$key]['length']) && ($rules['parameters'][$key]['length']['min'] > mb_strlen($param, 'utf-8') || $rules['parameters'][$key]['length']['max'] < mb_strlen($param, 'utf-8') )) {
                    $message = array('en' => '', 'zh-CN' => '参数长度限制在:' . $key);
                    return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_LENGTH'], $message);
                }
                if ($param !== '' && isset($rules['parameters'][$key]['value'])) {
                    $valueIsRight = FALSE; //标记是否通过value验证
                    foreach ($rules['parameters'][$key]['value'] as $val) {
                        //特殊参数：isPhone,isEmail,isNumber,isFloat
                        if ($val === 'isPhone' && with(new CommonUtils($request))->isEmailorPhone($param) === 2) {
                            $valueIsRight = TRUE;
                            break;
                        } else if ($val === 'isEmail' && with(new CommonUtils($request))->isEmailorPhone($param) === 1) {
                            $valueIsRight = TRUE;
                            break;
                        } else if ($val === 'isNumber' && is_numeric($param)) {
                            if ($key === 'size' && $param <= 0) { //size 大于 0
                                break;
                            }
                            $valueIsRight = TRUE;
                            break;
                        } else if ($val === 'isFloat' && ( is_float($param) || is_numeric($param) )) {
                            $valueIsRight = TRUE;
                            break;
                        } else if ($val === $param) {
                            //普通固定参数
                            $valueIsRight = TRUE;
                            break;
                        }
                    }
                    if (!$valueIsRight) {
//							echo '参数格式有误'.$key;
                        return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_VLAUE']);
                    }
                }
                if ($param !== '' && isset($rules['parameters'][$key]['isUser'])) { //username 是否验证用户名(isUser:true 验证用户必须存在 false 验证用户必须不存在)：目前用户名只有phone 和email
                    $ret = with(new CommonUtils($request))->isEmailorPhone($param);
                    if ($ret === 1) {
                        $info['email'] = $param;
                        //判断是否已经注册过
                        if (with(new User($request))->isBindEmail($info) != 1 && $rules['parameters'][$key]['isUser']) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNREGISTER']);
                        } elseif (with(new User($request))->isBindEmail($info) == 1 && !$rules['parameters'][$key]['isUser']) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_ALREADY_REGISTER']);
                        }
                    } else if ($ret === 2) {
                        //判断是否已经注册过
                        $info['phone'] = $param;
                        if (with(new User($request))->isBindPhone($info) != 1 && $rules['parameters'][$key]['isUser']) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNREGISTER']);
                        } elseif (with(new User($request))->isBindPhone($info) == 1 && !$rules['parameters'][$key]['isUser']) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_ALREADY_REGISTER']);
                        }
                    } else {
                        return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNREGISTER']);
                    }
                }
                //解析UUid 至 id
                if ($param !== '' && isset($rules['parameters'][$key]['isUUid']) && $rules['parameters'][$key]['isUUid']) { //isUUid 
                    $uid = with(new CommonUtils($request))->getId($param);
                    $request->merge(array($key => $uid));
                }

                if ($param !== '' && isset($rules['parameters'][$key]['isUserId']) && $rules['parameters'][$key]['isUserId']) { //userId 是否用户ID存在数据库
                    $uid = with(new CommonUtils($request))->getId($param);
                    if (!$uid) {
                        return $returnUtils->returnError($returnUtils->return['ERROR_USER_GETINFO']); //用户不存在，获取用户失败
                    }
//                        if(!with(new User())->getUserByUuid($param)){
//							return $returnUtils->returnError($returnUtils->return['ERROR_USER_GETINFO']); //用户不存在，获取用户失败
//						}
                }
                if ($param !== '' && isset($rules['parameters'][$key]['isLiveId']) && $rules['parameters'][$key]['isLiveId']) { //liveId 是否直播ID存在数据库
                    $uid = with(new CommonUtils($request))->getId($param);
                    if (!$uid) {
                        return $returnUtils->returnError($returnUtils->return['ERROR_USER_GETINFO']); //用户不存在，获取用户失败
                    }
                }

                if ($param !== '' && isset($rules['parameters'][$key]['checkStop']) && $rules['parameters'][$key]['checkStop']) { //敏感词过滤
                    if (with(new Stopwords())->isExistStopWords($param)) {//存在敏感词
                        return $returnUtils->returnError($returnUtils->return['ERROR_STOPWORD_LIMIT']);
                    }
                }
            }
            $request->merge(array('loginStatus' => '0'));
            //登录验证
            if ($rules['authType'] === 1) { //客户端
//            if(0){
                $dk = $request->input('dk');
                $tn = $request->input('tn');
                $uid = $request->input('userId');
                $user = null;
                if($uid){
                    $user = with(new User($request))->getUserById((int) $uid);
                }
                //检查用户是否	登陆
                if($user && isset($user->token)){ //登陆状态
                    $tokens = json_decode($user->token,TRUE);
                    if(isset($tokens[$dk]) && $tokens[$dk]['tn'] == $tn){
                        //登陆状态
                        $request->merge(array('loginStatus' => '1'));
                    } else if ($rules['auth']) {
                        return $returnUtils->returnError($returnUtils->return['ERROR_USER_TOKEN']);
                    }
                }else if ($rules['auth']) {
                    return $returnUtils->returnError($returnUtils->return['ERROR_USER_TOKEN']);
                }
            } else if ($rules['authType'] === 2) { //web登录
//					取auth
//                    $user = Auth::user();
//                    if (!$user) {
//                        if ($rules['auth'] == TRUE) {
//                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNLOGIN']);
//                        }
//                    }
            }
            //是否debug
            if ($this->DEBUG == TRUE && $rules['debug'] == TRUE) {
                return $rules['return'];
            }
            
/***********************请求缓存层**************************** */
    //      直接return不经过AfterMiddelware
            if(isset($rules['cache']['name']) && $this->CACHE_ON){
                GLOBAL $cache;
                $cache = new BaseCache();
                $cache->method = 'get';
                $cache->cacheName = $rules['cache']['name'];
                $par =array();
                if(isset($rules['cache']['par'])){
                    foreach ($rules['cache']['par'] as $value) {
                        if($value == 'EPG_ID'){
                            $par[] = env('EPG_ID');
                        } else if($value == 'SERVER_ADDRESS'){
                            $par[] = $_SERVER['REQUEST_URI'];
                        }else{
                            $par[] = $request->input($value);
                        }
                    }
                }
                $cache->cachePar = $par;
                $retCache = $cache->HandleCache();
                if($retCache !== 'NO_CACHE' && $retCache !== 'ERROR_CACHE'){
                    return $retCache;
                }
                $cache->method = 'put';
                $cache->cacheValue = 'EMPTY_CACHE'; //集合
                $cache->HandleCache();
            }
        }
        GLOBAL $gRedis;
        $gRedis = new Redis();
        $gRedis->connect(env('REDIS_HOST'), env('REDIS_PORT'));
        $gRedis->auth(env('REDIS_PWD'));
        return $next($request);
    }

}
